<?php

/**
 * This file is part of Webman AI.
 *
 * @author    walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link      http://www.workerman.net/
 */

namespace plugin\ai\app\handler\driver;

use Workerman\Http\Client;
use Workerman\Http\Response;

class Qwen extends Base
{
    /**
     * @var string api地址
     */
    protected $api = 'https://dashscope.aliyuncs.com';

    /**
     * 请求
     * @param $data
     * @param $options
     * @return void
     */
    public function completions($data, $options)
    {
        $headers = $this->getHeaders($options);
        $headers['Authorization'] = 'Bearer ' . $this->apikey;
        if (isset($options['stream'])) {
            $data['stream'] = true;
        }
        if ($data['stream'] ?? false) {
            $headers['Accept'] = 'text/event-stream';
        }
        $options = $this->formatOptions($options);
        $data = static::formatData($data);
        $requestOptions = [
            'method' => 'POST',
            'data' => json_encode($data),
            'headers' => $headers,
            'progress' => function ($buffer) use ($options) {
                static $tmp = '', $sentLen = 0;
                $tmp .= $buffer;
                if ($tmp[strlen($tmp) - 1] !== "\n") {
                    return;
                }
                foreach (array_reverse(explode("\n", $buffer)) as $chunk) {
                    if (preg_match('/data:/', $chunk)) {
                        $chunk = substr($chunk, 5);
                        $json = json_decode($chunk, true);
                        if (!$json) {
                            continue;
                        }
                        $data = array_merge(['content' => ''], $json);
                        if (isset($json['output']['text'])) {
                            $string = $json['output']['text'];
                            $len = $sentLen;
                            $sentLen = strlen($string);
                            $string = substr($string, $len);
                            $data['content'] = $string;
                        }
                        if (isset($json['message']) && $json['message'] !== '') {
                            $data = ['error' => ['code' => $json['code'] ?? 500, 'message' => $json['message'], 'detail' => $chunk]];
                        }
                        $options['stream']($data);
                        return;
                    }
                }
            },
            'success' => function (Response $response) use ($options) {
                $options['complete'](static::formatResponse((string)$response->getBody()), $response);
            },
            'error' => function ($exception) use ($options) {
                $options['complete']([
                    'error' => [
                        'code' => 'exception',
                        'message' => $exception->getMessage(),
                        'detail' => (string) $exception
                    ],
                ], new Response(0));
            }
        ];
        $http = new Client(['timeout' => 600]);
        $http->request("$this->api/api/v1/services/aigc/text-generation/generation", $requestOptions);
    }

    /**
     * 格式化消息
     * @param array $data
     * @return array
     */
    protected static function formatData(array $data)
    {
        if (isset($data['input'])) {
            return $data;
        }
        $model = $data['model'] ?? '';
        $temperature = $data['temperature'] ?? null;
        $messages = static::formatMessages($data['messages']);
        $data = [
            'model' => $model,
            'input' => [
                'messages' => $messages
            ]
        ];
        if ($temperature !== null) {
            $data['parameters'] = [
                'temperature' => $temperature
            ];
        }
        return $data;
    }

    public static function formatResponse($buffer)
    {
        $json = json_decode($buffer, true);
        if ($json) {
            if ($content = $json['output']['text'] ?? '') {
                return $content;
            }
            return $buffer;
        }
        foreach (array_reverse(explode("\n", $buffer)) as $chunk) {
            if (preg_match('/data:/', $chunk)) {
                $json = json_decode(substr($chunk, 5), true);
                if (isset($json['output']['text'])) {
                    return $json['output']['text'];
                }
                if (!empty($json['message'])) {
                    return json_encode($json, JSON_UNESCAPED_UNICODE);
                }
            }
        }
        return $buffer;
    }

}